/*
REWRITTEN FROM SCRATCH BY XINEF, IT OWNS NOW!
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "SpellAuras.h"
#include "SpellScript.h"

enum misc
{
	// ACTIONS
	ACTION_GUARDIAN_DIED			= 1,
};

enum spells
{
	// NADOX
    SPELL_BROOD_PLAGUE				= 56130,
    SPELL_BROOD_PLAGUE_H			= 59467,
    SPELL_BROOD_RAGE_H				= 59465,
    SPELL_ENRAGE					= 26662, // Enraged if too far away from home
    //SPELL_SUMMON_SWARMERS			= 56119, //2x 30178  -- 2x every 10secs, spell works fine but i need specific coords
    //SPELL_SUMMON_SWARM_GUARD		= 56120, //1x 30176  -- at 50%hp, spell works fine but i need specific coords

	// ADDS
	SPELL_SPRINT					= 56354,
    SPELL_GUARDIAN_AURA				= 56151,
	SPELL_SWARMER_AURA				= 56158,
};

enum creatures
{
    NPC_AHNKAHAR_SWARMER			= 30178,
    NPC_AHNKAHAR_GUARDIAN_ENTRY		= 30176,
};

enum events
{
	EVENT_CHECK_HEALTH				= 1,
	EVENT_CHECK_HOME				= 2,
	EVENT_PLAGUE					= 3,
	EVENT_BROOD_RAGE				= 4,
	EVENT_SWARMER					= 5,
	EVENT_SUMMON_GUARD				= 6,
};

enum sounds
{
	SOUND_AGGRO						= 14033,
	SOUND_SUMMON1					= 14034,
	SOUND_SUMMON2					= 14035,
	SOUND_SLAY1						= 14036,
	SOUND_SLAY2						= 14037,
	SOUND_SLAY3						= 14038,
	SOUND_DEATH						= 14039,
};

#define EMOTE_HATCHES		 "An Ahn'kahar Guardian hatches!"

class boss_elder_nadox : public CreatureScript
{
public:
    boss_elder_nadox() : CreatureScript("boss_elder_nadox") { }

    struct boss_elder_nadoxAI : public ScriptedAI
    {
        boss_elder_nadoxAI(Creature *c) : ScriptedAI(c), summons(me)
        {
            pInstance = c->GetInstanceScript();
        }

		EventMap events;
        InstanceScript *pInstance;
		SummonList summons;

		void SummonHelpers(bool swarm)
		{
			Creature *cr;
			if (swarm)
			{
				if (cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 640.425f, -919.544f, 25.8701f, 2.56563f))
					summons.Summon(cr);
				if (cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 655.891f, -930.445f, 25.6978f, 3.64774f))
					summons.Summon(cr);
			}
			else
			{
				if (cr = me->SummonCreature(NPC_AHNKAHAR_GUARDIAN_ENTRY, 658.677f, -934.332f, 25.6978f, 3.03687f))
					summons.Summon(cr);
			}
		}

        void Reset()
        {
			events.Reset();
			summons.DespawnAll();

            if (pInstance)
			{
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED);
				pInstance->SetData(DATA_NADOX_ACHIEVEMENT, true);
			}
        }

        void EnterCombat(Unit * /*who*/)
        {
			me->MonsterYell("The secrets of the deep shall remain hidden.", LANG_UNIVERSAL, 0);
			me->PlayDirectSound(SOUND_AGGRO);

			events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
			events.ScheduleEvent(EVENT_SWARMER, 10000);
			events.ScheduleEvent(EVENT_CHECK_HOME, 2000);
			events.ScheduleEvent(EVENT_PLAGUE, 5000+rand()%3000);
			events.ScheduleEvent(EVENT_BROOD_RAGE, 5000);

            if (pInstance)
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS);
        }

		void DoAction(int32 param)
		{
			if (param == ACTION_GUARDIAN_DIED)
			{
				if (pInstance)
					pInstance->SetData(DATA_NADOX_ACHIEVEMENT, false);
			}
		}

        void KilledUnit(Unit * /*victim*/)
        {
			if (urand(0,1))
				return;

			switch (rand()%3)
			{
				case 0:	
					me->MonsterYell("Sleep now, in the cold dark.", LANG_UNIVERSAL,0);
					me->PlayDirectSound(SOUND_SLAY1);
					break;
				case 1: 
					me->MonsterYell("For the Lich King!", LANG_UNIVERSAL,0);
					me->PlayDirectSound(SOUND_SLAY2);
					break;
				case 2: 
					me->MonsterYell("Perhaps we will be allies soon.", LANG_UNIVERSAL,0);
					me->PlayDirectSound(SOUND_SLAY3);
					break;
			}
        }

        void JustDied(Unit* /*killer*/)
        {
			events.Reset();
			summons.DespawnAll();
			
			me->MonsterYell("Master, is my service complete?", LANG_UNIVERSAL, 0);
			 me->PlayDirectSound(SOUND_DEATH);
            if (pInstance)
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, DONE);
        }

		void JustSummoned(Creature* cr)
		{
			if (cr)
			{
				if (cr->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY )
				{
					switch (rand()%2)
					{
						case 0: 
							me->MonsterYell("The young must not grow hungry...", LANG_UNIVERSAL, 0);
							me->PlayDirectSound(SOUND_SUMMON1);
							break;
						case 1: 
							me->MonsterYell("Shhhad ak kereeesshh chak-k-k!", LANG_UNIVERSAL, 0);
							me->PlayDirectSound(SOUND_SUMMON2);
							break;
					}
				}
				
				summons.Summon(cr);
			}
		}
        void UpdateAI(uint32 diff)
        {
            if (!UpdateVictim())
                return;

			events.Update(diff);

			if( me->HasUnitState(UNIT_STATE_CASTING) )
				return;

			switch ( events.GetEvent() )
			{
				case EVENT_CHECK_HEALTH:
				{
					events.RepeatEvent(1000);
					if (HealthBelowPct(50))
					{
						events.CancelEvent(EVENT_CHECK_HEALTH);
						events.ScheduleEvent(EVENT_SUMMON_GUARD, 100);
					}
					break;
				}
				case EVENT_SUMMON_GUARD:
				{
					me->MonsterTextEmote(EMOTE_HATCHES, me, true);
					SummonHelpers(false);
					events.PopEvent();
					break;
				}
				case EVENT_BROOD_RAGE:
				{
					if (Creature *pSwarmer = me->FindNearestCreature(NPC_AHNKAHAR_SWARMER, 40, true))
						me->CastSpell(pSwarmer, SPELL_BROOD_RAGE_H, true);
					
					events.RepeatEvent(10000);
					break;
				}
				case EVENT_PLAGUE:
				{
					me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_BROOD_PLAGUE, SPELL_BROOD_PLAGUE_H), false);
					events.RepeatEvent(12000+rand()%5000);
					break;
				}
				case EVENT_SWARMER:
				{
					SummonHelpers(true);
					events.RepeatEvent(10000);
					break;
				}
				case EVENT_CHECK_HOME:
				{
					if (me->HasAura(SPELL_ENRAGE))
						break;

					if (me->GetPositionZ() < 24)
					{
						me->CastSpell(me, SPELL_ENRAGE, true);
						events.PopEvent();
						break;
					}

					events.RepeatEvent(2000);
					break;
				}
			}

			DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new boss_elder_nadoxAI(creature);
    }
};

class npc_ahnkahar_nerubian : public CreatureScript
{
public:
    npc_ahnkahar_nerubian() : CreatureScript("npc_ahnkahar_nerubian") { }

    struct npc_ahnkahar_nerubianAI : public ScriptedAI
    {
        npc_ahnkahar_nerubianAI(Creature *c) : ScriptedAI(c) { }

        
        uint32 uiSprintTimer;
        void Reset()
        {
            if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
				me->CastSpell(me, SPELL_GUARDIAN_AURA, true);
			else // Swarmers
				me->CastSpell(me, SPELL_SWARMER_AURA, true);
            
			if (me->GetEntry() == NPC_AHNKAHAR_SWARMER || me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
				me->SetInCombatWithZone();

			uiSprintTimer = 10000;
        }

        void JustDied(Unit * /*killer*/)
        {
            if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
			{
                if (InstanceScript *pInstance = me->GetInstanceScript()) 
					if (Creature *nadox = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_ELDER_NADOX)))
						nadox->AI()->DoAction(ACTION_GUARDIAN_DIED);

				me->RemoveAllAuras();
			}
        }

        void UpdateAI(uint32 diff)
        {
            if (!UpdateVictim())
                return;

            if (uiSprintTimer <= diff)
            {
                me->CastSpell(me, SPELL_SPRINT, false);
                uiSprintTimer = 15000;
            }
			else 
				uiSprintTimer -= diff;

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new npc_ahnkahar_nerubianAI(creature);
    }
};

class spell_ahn_kahet_swarmer_aura : public SpellScriptLoader
{
	public:
		spell_ahn_kahet_swarmer_aura() : SpellScriptLoader("spell_ahn_kahet_swarmer_aura") { }

		class spell_ahn_kahet_swarmer_aura_SpellScript : public SpellScript
		{
			PrepareSpellScript(spell_ahn_kahet_swarmer_aura_SpellScript)

			void HandleDummy(SpellEffIndex /*effIndex*/)
			{
				Unit* caster = GetCaster();
				std::list<Creature*> swarm, swarm2;
				caster->GetCreaturesWithEntryInRange(swarm, 40.0f, 30338);
				caster->GetCreaturesWithEntryInRange(swarm2, 40.0f, 30178);
				int32 aliveCount = -1; // minus self

				std::list<Creature*>::const_iterator itr;
				for (itr = swarm.begin(); itr != swarm.end(); ++itr)
					if ((*itr)->IsAlive())
						aliveCount++;
				for (itr = swarm2.begin(); itr != swarm2.end(); ++itr)
					if ((*itr)->IsAlive())
						aliveCount++;

				if (Aura *aur = caster->GetAura(56281))
				{
					if (aliveCount > 0)
						aur->SetStackAmount(aliveCount);
					else
						aur->Remove();
				}
				else if (aliveCount > 0)
				{
					caster->CastCustomSpell(caster, 56281, &aliveCount, &aliveCount, &aliveCount, true);
					if (Aura *aur = caster->GetAura(56281))
						aur->SetStackAmount(aliveCount);
				}
			}

			void Register()
			{
				OnEffectHitTarget += SpellEffectFn(spell_ahn_kahet_swarmer_aura_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
			}
		};

		SpellScript* GetSpellScript() const
		{
			return new spell_ahn_kahet_swarmer_aura_SpellScript();
		}
};

void AddSC_boss_elder_nadox()
{
    new boss_elder_nadox();
    new npc_ahnkahar_nerubian();
	new spell_ahn_kahet_swarmer_aura();
}
